using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace 视觉
{
    public partial class Form1 : Form
    {

        // 摄像头捕获对象
        private VideoCapture capture;
        // 背景减除器
        private BackgroundSubtractorMOG2 backgroundSubtractor;
        // 轨迹点集合
        private List<OpenCvSharp.Point> trajectoryPoints = new List<OpenCvSharp.Point>();
        // 绘图定时器
        private System.Windows.Forms.Timer timer;
        // 显示窗口
        private PictureBox displayBox;

        public Form1()
        {
            InitializeComponent();
            SetupUI();
            InitializeMotionTracking();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }


        private void SetupUI()
        {
            this.Text = "物体运动轨迹监控";
            this.Size = new System.Drawing.Size(1024, 768);

            displayBox = new PictureBox
            {
                Dock = DockStyle.Fill,
                SizeMode = PictureBoxSizeMode.Zoom
            };
            this.Controls.Add(displayBox);

            // 定时器, 每30毫秒执行一次
            timer = new System.Windows.Forms.Timer { Interval = 30 };
            // 绑定定时器事件
            timer.Tick += Timer_Tick;
        }

        private void InitializeMotionTracking()
        {
            // 初始化摄像头捕获 (0表示默认摄像头)
            capture = new VideoCapture(0);
            if (!capture.IsOpened())
            {
                MessageBox.Show("无法打开摄像头！");
                return;
            }

            // 初始化背景减除器
            backgroundSubtractor = BackgroundSubtractorMOG2.Create(history: 500, varThreshold: 16, detectShadows: true);

            // 启动定时器
            timer.Start();
        }

        /// <summary>
        /// 定时器事件处理函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Timer_Tick(object sender, EventArgs e)
        {
            using var frame = new Mat();
            using var fgMask = new Mat();
            using var contourImage = new Mat();

            // 读取一帧
            if (!capture.Read(frame))
            {
                MessageBox.Show("无法读取帧！");
                timer.Stop();
                return;
            }

            // 应用背景减除
            backgroundSubtractor.Apply(frame, fgMask);

            // 图像预处理
            Cv2.GaussianBlur(fgMask, fgMask, new OpenCvSharp.Size(5, 5), 0);
            Cv2.Threshold(fgMask, fgMask, 127, 255, ThresholdTypes.Binary);

            // 形态学操作，消除噪声
            var kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new OpenCvSharp.Size(5, 5));
            Cv2.MorphologyEx(fgMask, fgMask, MorphTypes.Open, kernel);
            Cv2.MorphologyEx(fgMask, fgMask, MorphTypes.Close, kernel);

            // 查找轮廓
            Cv2.FindContours(fgMask, out OpenCvSharp.Point[][] contours, out HierarchyIndex[] hierarchy,
                             RetrievalModes.External, ContourApproximationModes.ApproxSimple);

            // 复制原始帧用于显示
            frame.CopyTo(contourImage);

            // 分析轮廓并绘制轨迹
            if (contours.Length > 0)
            {
                // 找到最大轮廓
                double maxArea = 0;
                int maxIndex = 0;
                for (int i = 0; i < contours.Length; i++)
                {
                    double area = Cv2.ContourArea(contours[i]);
                    if (area > maxArea)
                    {
                        maxArea = area;
                        maxIndex = i;
                    }
                }

                // 只处理足够大的轮廓
                if (maxArea > 500)
                {
                    // 计算轮廓的边界框和中心点
                    var boundingRect = Cv2.BoundingRect(contours[maxIndex]);
                    Cv2.Rectangle(contourImage, boundingRect, new Scalar(0, 255, 0), 2);

                    // 计算轮廓的矩
                    var moments = Cv2.Moments(contours[maxIndex]);
                    if (moments.M00 != 0)
                    {
                        int cx = (int)(moments.M10 / moments.M00);
                        int cy = (int)(moments.M01 / moments.M00);

                        // 绘制中心点
                        Cv2.Circle(contourImage, new OpenCvSharp.Point(cx, cy), 5, new Scalar(0, 0, 255), -1);

                        // 添加到轨迹点集合
                        trajectoryPoints.Add(new OpenCvSharp.Point(cx, cy));

                        // 限制轨迹点数量，避免内存溢出
                        if (trajectoryPoints.Count > 100)
                        {
                            trajectoryPoints.RemoveAt(0);
                        }
                    }
                }
            }

            // 绘制轨迹
            for (int i = 1; i < trajectoryPoints.Count; i++)
            {
                Cv2.Line(contourImage, trajectoryPoints[i - 1], trajectoryPoints[i], new Scalar(255, 0, 0), 2);
            }

            // 显示结果
            displayBox.Image = BitmapConverter.ToBitmap(contourImage);
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            timer?.Stop();
            capture?.Release();
            backgroundSubtractor?.Dispose();
        }
    }
}
